Skip to content

Add ZFSDDTStats for OpenZFS dedup table (DDT) stats - #878

Open
natneam wants to merge 1 commit into
prometheus:masterfrom
natneam:zfs-ddt-stats
Open

natneam wants to merge 1 commit into
prometheus:masterfrom
natneam:zfs-ddt-stats

Conversation

@natneam

@natneam natneam commented Oct 5, 2026

Copy link
Copy Markdown

Adds a parser for the OpenZFS dedup table (DDT) statistics in
/proc/spl/kstat/zfs/<pool>/ddt_stats_<checksum>, so node_exporter's zfs
collector can expose them (see prometheus/node_exporter#3435). This is the first
ZFS code in procfs.

What it does

FS.ZFSDDTStats() globs spl/kstat/zfs/*/ddt_stats_* and returns one
ZFSDDTStats per file:

  • Pool and checksum come from the path (parent directory name, and the
    filename with ddt_stats_ trimmed). A DDT belongs to the whole pool, so
    there is no dataset.
  • One file per dedup-capable checksum. ZFS creates sha256, sha512, skein,
    edonr and blake3 files for every pool, and only the checksum in use has
    non-zero values.
  • Format: the files are named kstats (name type data). The three
    *_rate fields are KSTAT_DATA_UINT32; the rest are KSTAT_DATA_UINT64.
    All of them are returned as uint64.
  • Unknown field names are ignored, so fields added in later ZFS versions
    don't break parsing.
  • No files means an empty result, not an error. That covers OpenZFS older
    than 2.3 and systems without ZFS.

Field definitions are in ddt_kstats_template in
module/zfs/ddt.c.
The counters reset each time the pool is imported.

Reading is done with parsers.ReadFileNoStat (these files report size 0),
and parsing is a separate function, following CONTRIBUTING.md.

Testing

  • Fixtures: ddt_stats_sha256 and ddt_stats_blake3 for pool1,
    captured unmodified from OpenZFS 2.3 on Debian 13.
  • Fixture test: compares the full parsed result for both files, including
    the UINT32 rate fields. The sha256 values are internally consistent, e.g.
    lookup 800 = lookup_new 400 + lookup_existing 400.
  • Parser test: a table test for parseZFSDDTStats covering empty input,
    a missing header, a non-numeric value, an unknown field name, an unexpected
    type, and a UINT32 row.
  • make test and make lint pass.

Follow-up

Once this is released, I'll open a node_exporter PR that uses
fs.ZFSDDTStats() to add DDT metrics to the zfs collector. That adds 17
metrics per checksum file, which is 85 series per pool (5 checksums × 17
fields).

cc @SuperQ @discordianfish

Add FS.ZFSDDTStats, which reads the OpenZFS dedup table (DDT) statistics
from /proc/spl/kstat/zfs/<pool>/ddt_stats_<checksum>. These files exist
on OpenZFS 2.3 and later, one per dedup-capable checksum per pool.

Pool and checksum are taken from the file path. Rows are parsed from the
named kstat table; both UINT32 (the *_rate fields) and UINT64 values are
returned as uint64, and unknown field names are ignored so that new ZFS
fields do not break parsing. A system without these files returns an
empty result rather than an error.

Fixtures are captured from OpenZFS 2.3 on Debian 13.

This is needed for node_exporter's zfs collector:
prometheus/node_exporter#3435

Signed-off-by: Natneam M <58377289+natneam@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant